HandStack으로 게시판 프로젝트 시작하기

게시판의 요구사항을 화면·DB·계약으로 나누고 한 번의 조회를 연결합니다.

QCN

왜 게시판 프로젝트인가? (1/2)

처음 개발을 시작할 때 게시판 만들기는 가장 기본적인 프로젝트로 권장됩니다.
게시판 예제는 HandStack 기반 개발의 핵심 개념을 이해하고 실습하는 데 매우 유용합니다.

  • 웹 페이지 화면 구성

    • Tabler CSS Framework 기반의 레이아웃과 디자인 학습
  • 서버 데이터 통신 처리

    • HandStack의 거래(Transaction) 과정 이해
QCN

왜 게시판 프로젝트인가? (2/2)

  • 데이터베이스 처리
    • 계약(Contracts) 기반 데이터 상호작용 방법 학습
QCN

개발 보조 도구: 생성형 AI

이 프로젝트에서는 Google Gemini을 참고 자료로 활용합니다.

https://gemini.google.com/app

  • 요구사항·DDL·CRUD의 초안을 요청하고 실행 전 사람이 검토합니다.
  • 실제 개인정보·비밀번호·운영 데이터를 입력하지 않습니다.
  • 다른 도구를 사용해도 같은 입력과 검증 기준을 적용합니다.
QCN

사용자 스토리 만들기 (1/2)

성공적인 프로젝트를 위해 가장 먼저 할 일은 사용자를 정의하고 요구사항을 명확히 하는 것입니다.

  • 페르소나 (Persona)
    • 이 프로젝트의 사용자는 "개발자" 본인 1명으로 한정합니다.
QCN

사용자 스토리 만들기 (2/2)

  • 핵심 요구사항
    • 서식과 이미지를 포함하는 글 작성 (위지윅 에디터)
    • "정보, 강좌, 소식" 등 글 분류 기능
    • 화면 전환 없는 빠른 수정 및 삭제
    • 최신순 보기, "분류, 기간, 제목" 조건 검색 (기간 기본값: 최근 1달)
    • 목록에서 "분류, 기간, 제목, 입력시간" 기준 정렬
QCN

화면과 기능 설계하기

사용자 스토리를 기반으로 필요한 화면과 기능을 구체화합니다.

  • 게시글 목록 화면 (BOD010)
    • 조회 필터, 목록 정렬, 신규 등록/상세 조회 화면 호출
  • 신규 게시글 등록 화면 (BOD011)
    • 위지윅 에디터, 제목/본문/작성자 입력
  • 기존 게시글 편집 및 삭제 화면 (BOD012)
    • 게시글 정보 조회, 편집, 삭제 기능

HandStack에서 기본 제공하는 기능들로 대부분 개발이 가능합니다.

QCN

프로젝트 구조화

신뢰와 합의의 결과물인 소스코드는 일관된 규칙으로 관리되어야 합니다.

  • 작업 항목 ID 분류
    • BOD: 게시판 프로젝트 ID
    • BOD010: 게시글 목록
    • BOD011: 게시글 신규 등록
    • BOD012: 게시글 편집 및 삭제
QCN

디렉토리 및 파일 구성

Contracts
├─dbclient/HDS/BOD
│  ├─BOD010.xml
│  ├─BOD011.xml
│  └─BOD012.xml
├─transact/HDS/BOD
│  ├─BOD010.json
│  ├─BOD011.json
│  └─BOD012.json
└─wwwroot/HDS/BOD
   ├─BOD010.html, BOD010.js
   ├─BOD011.html, BOD011.js
   └─BOD012.html, BOD012.js
QCN

4단계: 데이터베이스 설계

HandStack은 SQL Server, Oracle, MySQL/MariaDB, PostgreSQL, SQLite 등 다양한 데이터베이스를 지원합니다.
게시판 프로젝트에서는 별도 서버 설치 없이 바로 시작할 수 있는 SQLite를 사용합니다.

  • Gemini 에게 테이블 설계 요청하기

간단한 분류 게시판 데이터베이스 테이블 정보 (컬럼명, 데이터 타입, 설명)를 SQLite 기준으로 MarkDown 문법으로 만들어줘. 그리고 실행 결과에서 테이블을 생성 하는 ddl 문법에서 ID를 자동 증가 키 컬럼으로 구성하고 기존 테이블이 없으면 CREATE 하는 예제를 알려줘

QCN

Gemini 의 답변: 테이블 DDL

SQLite 기준으로 분류 게시판 데이터베이스 테이블을 만들었습니다.

컬럼명 데이터 타입 설명
ID INTEGER 게시글의 고유 번호 (기본 키)
Category TEXT 게시글의 카테고리
Title TEXT 게시글의 제목
Content TEXT 게시글의 내용
Author TEXT 게시글 작성자의 이름
DatePosted TEXT 게시글이 작성된 날짜와 시간
QCN

Gemini 의 답변: CRUD 쿼리 (1/2)

위의 Board 테이블 결과에서 SQLite 기준으로 CRUD 쿼리를 만들어줘

실습 DB에서만 실행합니다. UPDATE·DELETE는 대상 ID와 WHERE 조건을 확인한 뒤 수행합니다.

  1. Create (생성)
INSERT INTO Board (Category, Title, Content, Author, DatePosted)
VALUES ('카테고리', '제목', '내용', '작성자', datetime('now', 'localtime'));
  1. Read (조회)
QCN

Gemini 의 답변: CRUD 쿼리 · 조회

SELECT * FROM Board WHERE ID = 1;
QCN

CRUD 쿼리 · 수정과 삭제

  1. Update (수정)
UPDATE Board SET Title = '새 제목', Content = '새 내용' WHERE ID = 1;
  1. Delete (삭제)
DELETE FROM Board WHERE ID = 1;
QCN

쿼리 적용 (dbclient 모듈)

Gemini 이 생성한 쿼리를 HandStack의 계약(Contract) 파일에 적용합니다.

  • 기능 ID 규칙

    • 기능(1) + 명령구분(1) + 순번(2) = 4자리 ID (예: LD01: List + Database + 01)
    • 명령구분: D(Database), F(Function), A(API), T(Task)
    • 기능: I(Insert), U(Update), D(Delete), G(Get), L(List), M(Modify)
  • 이 규칙은 프로젝트의 모든 모듈에 동일하게 적용되어 일관성을 유지합니다.

QCN

dbclient 계약 파일 예시: BOD010.xml (1/3)

데이터베이스 쿼리는 XML 파일로 관리하며, SQL과 파라미터 매핑을 직접 제어합니다.
이를 통해 복잡한 쿼리 튜닝과 소스 버전 관리가 용이합니다.

QCN

dbclient 계약 파일 예시: BOD010.xml (2/3)

<!-- contracts/dbclient/HDS/BOD/BOD010.xml -->
<mapper xmlns="contract.xsd">
    <header>
        <application>HDS</application>
        <project>BOD</project>
        <transaction>BOD010</transaction>
        <datasource>DB01</datasource>
    </header>
    <commands>
        <statement id="LD01" desc="분류, 기간, 제목을 기준으로 게시글 조회">
            <![CDATA[
SELECT B.ID, B.Category, B.Title, B.Author, B.DatePosted, '확인' AS EditPost
FROM Board B
WHERE B.DatePosted BETWEEN @StartDate AND DATEADD(day, 1, @EndDate)
QCN

dbclient 계약 파일 예시: BOD010.xml (3/3)

  AND (@Category = '' OR B.Category = @Category)
  AND (@Title = '' OR B.Title LIKE ('%' + @Title + '%'))
ORDER BY
  CASE WHEN @Sequence = 'ASC' THEN
    CASE @OrderBy WHEN 'ID' THEN CONVERT(VARCHAR, ID) WHEN 'Category' THEN Category ... END
  END ASC,
  CASE WHEN @Sequence = 'DESC' THEN
    CASE @OrderBy WHEN 'ID' THEN CONVERT(VARCHAR, ID) WHEN 'Category' THEN Category ... END
  END DESC;
            ]]>
        </statement>
    </commands>
</mapper>
QCN

잠깐, 구분해 보기

SQL 조회가 성공해도 화면이 비어 있다면 어느 계약을 대조할까요?

QCN

거래 요청 관리 (transact 모듈) (1/3)

이 예제의 거래 요청은 transact 실행 엔드포인트로 전달합니다. JSON 계약의 입력·출력과 서버 검증 설정을 함께 확인합니다. 계약 파일만으로 모든 인증·인가가 보장되지는 않습니다.

QCN

거래 요청 관리 (transact 모듈) (2/3)

{
    "ApplicationID": "HDS",
    "ProjectID": "BOD",
    "TransactionID": "BOD010",
    "Services": [
        {
            "ServiceID": "LD01",
            "Authorize": false,
            "ReturnType": "Json",
            "CommandType": "D",
            "Inputs": [ { "Type": "Row" } ],
            "Outputs": [ { "Type": "Grid" } ]
        }
    ]
QCN

거래 요청 관리 (transact 모듈) (3/3)

}
QCN

화면 개발 (wwwroot 모듈) (1/2)

화면은 웹 표준 기술(HTML, Javascript)과 오픈소스 CSS 프레임워크(Tabler)로 개발합니다.

  • 기본 HTML 구조
    • syn.loader.js가 개발/운영 환경에 맞게 필요한 리소스를 자동으로 로드합니다.
QCN

화면 개발 (wwwroot 모듈) (2/2)

<!DOCTYPE html>
<html>
<head>...</head>
<body>
  <form id="form1" syn-datafield="MainForm">
    <!-- 페이지 컨텐츠 -->
  </form>
  <script src="/js/syn.loader.js"></script>
</body>
</html>
  • 화면 디자인(HTML)과 업무 로직(JS)은 동일한 이름의 파일로 분리하여 관리합니다.
QCN

화면 개발 예시: HTML (BOD010.html) (1/4)

HTML 요소에 syn- 접두사를 가진 속성을 사용하여 선언적으로 UI와 데이터를 바인딩합니다.

  • 이벤트 처리기 및 UI 컨트롤 설정
QCN

화면 개발 예시: HTML (BOD010.html) (2/4)

<!-- 조회 버튼 -->
<button type="button" id="btnSearch" syn-events="['click']" class="btn">조회</button>

<!-- 조회 조건: 제목 -->
<input id="txtTitle" syn-datafield="Title" syn-options="{belongID: ['LD01']}">

<!-- 데이터 그리드 -->
<syn_grid id="grdBoard" syn-datafield="Board" syn-options="{
    height: 420,
    columns: [
        ['ID', '게시글 ID', 100],
        ['Title', '제목', 400],
        ['EditPost', '상세', 80, false, 'button']
    ]
QCN

화면 개발 예시: HTML (BOD010.html) (3/4)

}"></syn_grid>
QCN

화면 개발 예시: HTML (BOD010.html) (4/4)

  • syn.controls.js 라이브러리가 제공하는 다양한 UI 컴포넌트로 생산성을 높입니다.
QCN

화면 개발 예시: JavaScript (BOD010.js) (1/3)

업무 로직은 $BOD010과 같이 정해진 구조를 가진 Javascript 객체로 작성하여 일관성을 확보합니다.

QCN

화면 개발 예시: JavaScript (BOD010.js) (2/3)

'use strict';
let $BOD010 = {
    // 거래(Transaction) 정의
    transaction: {
        LD01: {
            inputs: [{ type: 'Row', dataFieldID: 'MainForm' }],
            outputs: [{ type: 'Grid', dataFieldID: 'Board' }]
        }
    },
    // 화면 로드 시 실행될 Hook
    hook: {
        pageLoad() {
            syn.$w.transactionAction('LD01'); // 페이지 로드 시 목록 조회
        }
QCN

화면 개발 예시: JavaScript (BOD010.js) (3/3)

    },
    // 사용자 이벤트 핸들러
    event: {
        btnSearch_click(evt) {
            syn.$w.transactionAction('LD01'); // 조회 버튼 클릭 시 목록 조회
        },
        grdBoard_cellButtonClick(elID, row, column, prop, value) {
            // 그리드 내 버튼 클릭 시 상세 팝업 열기
        }
    }
};
QCN

게시글 목록 (BOD010)

image center

QCN

신규 등록 (BOD011)

image center

QCN

편집·삭제 (BOD012)

image center

QCN

게시판의 완료 기준

  • BOD010·BOD011·BOD012의 목록·등록·편집 책임을 구분합니다.
  • AI 초안의 DDL·CRUD를 검토한 뒤 dbclient와 transact에 연결합니다.
  • 검색·정렬·등록·수정·삭제를 같은 테스트 데이터로 검증합니다.
QCN

발표: 첫 화면의 목표를 말한 뒤 핵심 개념과 예제로 진행합니다. 확인 질문 뒤에는 답할 시간을 주고, 마지막 완료 기준을 남겨 질문을 받습니다. 발표 구성 참고: MIT OpenCourseWare, Patrick Winston, How to Speak (2018), https://ocw.mit.edu/courses/res-tll-005-how-to-speak-january-iap-2018/pages/how-to-speak/

이어지는 코드 조각입니다. 앞뒤 페이지를 순서대로 읽으며 전체 예제의 일부임을 설명합니다.

이어지는 코드 조각입니다. 앞뒤 페이지를 순서대로 읽으며 전체 예제의 일부임을 설명합니다.

질문 후 잠시 기다립니다. 답이 없으면 앞에서 본 예제를 다시 가리킵니다. 확인할 답: transact Outputs와 화면 transaction 출력 매핑, 반환 컬럼을 대조합니다. 다음 주제로 넘어가기 전에 차이를 청중의 표현으로 한 번 확인합니다.

이어지는 코드 조각입니다. 앞뒤 페이지를 순서대로 읽으며 전체 예제의 일부임을 설명합니다.

이어지는 코드 조각입니다. 앞뒤 페이지를 순서대로 읽으며 전체 예제의 일부임을 설명합니다.

이어지는 코드 조각입니다. 앞뒤 페이지를 순서대로 읽으며 전체 예제의 일부임을 설명합니다.

이어지는 코드 조각입니다. 앞뒤 페이지를 순서대로 읽으며 전체 예제의 일부임을 설명합니다.

이어지는 코드 조각입니다. 앞뒤 페이지를 순서대로 읽으며 전체 예제의 일부임을 설명합니다.

이어지는 코드 조각입니다. 앞뒤 페이지를 순서대로 읽으며 전체 예제의 일부임을 설명합니다.

질문을 받는 동안 이 확인 기준을 화면에 남깁니다. 청중이 자신의 업무에 적용할 다음 행동 하나를 고르게 합니다.